/**
 * 
 */
package org.t2.game.server.module.data;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.gaming.fakecmd.annotation.PlayerCmd;
import org.gaming.tool.CryptoJSDecryptUtil;
import org.gaming.tool.ListMapUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.t2.game.server.foundation.player.PlayerContext;
import org.t2.game.server.module.data.model.Data;
import org.t2.game.server.module.data.service.DataParserService;
import org.t2.game.server.module.data.service.DataService;

import pb.t2.protobuf.data.Data.DataAddOrUpdateRequest;
import pb.t2.protobuf.data.Data.DataAddOrUpdateResponse;
import pb.t2.protobuf.data.Data.DataDeleteRequest;
import pb.t2.protobuf.data.Data.DataDeleteResponse;
import pb.t2.protobuf.data.Data.DataGetRequest;
import pb.t2.protobuf.data.Data.DataGetResponse;
import pb.t2.protobuf.data.Data.PbData;

/**
 * @author YY
 */
@Controller
public class DataHandler {
	
	private static Logger logger = LoggerFactory.getLogger(DataHandler.class);

	public static final String SECRET_KEY = "7a547a1f8e1b09d04b713259aa9d1097"; // 16 bytes key (128 bits)
	
	@Autowired
	private DataService dataService;
	
	@PlayerCmd
	public DataGetResponse get(PlayerContext playerContext, DataGetRequest request) {
		List<Data> datas = dataService.getEntities(playerContext.getId());
		
		DataGetResponse.Builder response = DataGetResponse.newBuilder();
		for(Data data : datas) {
			response.addDatas(build(data));
		}
		return response.build();
	}
	
	public PbData build(Data data) {
		PbData.Builder builder = PbData.newBuilder();
		builder.setId(data.getDataId());
		builder.setData(data.getData());
		return builder.build();
	}
	
	@PlayerCmd
	public DataAddOrUpdateResponse addOrUpdate(PlayerContext playerContext, DataAddOrUpdateRequest request) {
		List<Data> currDdatas = dataService.getModuelDatas(playerContext.getId(), request.getDataType());
		Map<Integer, Data> dataMap = ListMapUtil.listToMap(currDdatas, Data::getDataId);
		
		List<Data> insertDatas = new ArrayList<>();
		List<Data> updateDatas = new ArrayList<>();
		List<Data> updateLogDatas = new ArrayList<>();
		
		for(PbData pbData : request.getDatasList()) {
			Data data = dataMap.get(pbData.getId());
			if(data == null) {
				data = new Data();
				data.setPlayerId(playerContext.getId());
				data.setDataType(request.getDataType());
				data.setDataId(pbData.getId());
				data.setData(pbData.getData());
				String plaintext = CryptoJSDecryptUtil.decrypt(pbData.getData(), SECRET_KEY);
				data.setPlaintext(plaintext);
				
				insertDatas.add(data);
				dataMap.put(data.getDataId(), data);
			} else {
				data.setData(pbData.getData());
				String plaintext = CryptoJSDecryptUtil.decrypt(pbData.getData(), SECRET_KEY);
				if(!data.getPlaintext().equals(plaintext)) {
					updateLogDatas.add(data);
				}
				data.setPlaintext(plaintext);
				updateDatas.add(data);
			}
		}
		
		dataService.insert(insertDatas, request.getReason());
		dataService.update(updateDatas, updateLogDatas, request.getReason());
		currDdatas.addAll(insertDatas);
		
		//TODO 一大堆的数据解释
		DataParserService dataParserService = DataParserService.getService(request.getDataType());
		if(dataParserService != null) {
			try {
				dataParserService.parser(playerContext.getId(), currDdatas, request.getReason());
			} catch (Exception e) {
				logger.error("数据解释发生异常", e);
			}
		}
		
		DataAddOrUpdateResponse.Builder response = DataAddOrUpdateResponse.newBuilder();
		response.addAllDatas(request.getDatasList());
		return response.build();
	}
	
	@PlayerCmd
	public DataDeleteResponse delete(PlayerContext playerContext, DataDeleteRequest request) {
		List<Data> currDdatas = dataService.getModuelDatas(playerContext.getId(), request.getDataType());
		Map<Integer, Data> dataMap = ListMapUtil.listToMap(currDdatas, Data::getDataId);
		
		List<Data> deleteList = new ArrayList<>();
		for(int dataId : request.getDataIdsList()) {
			Data data = dataMap.get(dataId);
			deleteList.add(data);
		}
		dataService.delete(deleteList, request.getReason());
		
		DataDeleteResponse.Builder response = DataDeleteResponse.newBuilder();
		response.addAllDataIds(request.getDataIdsList());
		return response.build();
	}
}
